#include "fileTransfer.h"

/*
 * @brief 服务端处理客户端上传请求
 *
 * @param sockfd 连接客户端的socket文件描述符
 * @param mysql 连接到的数据库
 * @param file_path 文件在数据库中的路径
 * @param user_id 传入filePath_t 结构体用于获取用户唯一标识符 user_id
 *
 * @return 0-成功
 */
int uploadHandle(int sockfd, MYSQL *mysql,
                 const char *file_path, const filePath_t user_id)
{
    tlv_t server_tlv;
    fileCheck_t file_check;
    char file_name[FILE_NAME_MAX];
    int flag; // 传输标识

    // 接收文件SHA256校验是否续传
    recv(sockfd, &server_tlv, TLV_HEAD_SIZE, MSG_WAITALL);
    recv(sockfd, &file_check.sha256, server_tlv.length, MSG_WAITALL);
    isFileResume(mysql, file_check.sha256);

    // 全新上传or秒传or续传
    // 秒传 - 如果存在 sha256&&completed_file==true
    // 续传 - 如果当前用户目录下的 sha256&&completed_file==false
    // 全新上传 - 表中没有 sha256
    flag = isFileResume(mysql, file_check.sha256);

    server_tlv.type = TYPE_FLAG;
    server_tlv.length = flag;
    send(sockfd, &server_tlv, TLV_HEAD_SIZE, MSG_NOSIGNAL); // 用length传一个flag

    // 接收file_check用于接收数据
    recv(sockfd, &server_tlv, TLV_HEAD_SIZE, MSG_WAITALL);
    recv(sockfd, &file_check, server_tlv.length, MSG_WAITALL);

    if (flag == FILE_EXIST) // 秒传，跳过传输，直接插入一条记录即可
    {
        insertFileSkip(mysql, user_id, file_name, file_check.sha256);
        printf("传完鸟\n");
        return 0;
    }
    else if (flag == FILE_NOT_EXIST) // 全新上传
    {
        insertFileNew(mysql, user_id, &file_check);
        int fd = open(file_check.sha256, O_WRONLY | O_CREAT, 0644);
        serverRecvData(sockfd, fd, mysql, &file_check, file_path, user_id);
        close(fd);
    }
    else if (flag == FILE_RESUME) // 续传
    {
        // 发送offset
        server_tlv.type = TYPE_METADATA;
        server_tlv.length = sizeof(file_check.file_offset);
        send(sockfd, &server_tlv, TLV_HEAD_SIZE, MSG_NOSIGNAL);
        send(sockfd, &file_check.file_offset, server_tlv.length, MSG_NOSIGNAL);

        int fd = open(file_check.sha256, O_WRONLY, 0644);
        lseek(fd, file_check.file_offset, SEEK_SET); // 从offset开始写
        serverRecvData(sockfd, fd, mysql, &file_check, file_path, user_id);
        close(fd);
    }
    else
    {
        // 返回值出错
        printf("坏了 isFileResume返回了个啥\n");
        return -1;
    }

    return 0;
}

int serverRecvData(int sockfd, int fd, MYSQL *mysql,
                   fileCheck_t *file_check, const char *file_path, filePath_t user_id)
{
    tlv_t recv_tlv;
    char *data = (char *)malloc(CHUNK_SIZE);
    char sha256[SHA256_LENGTH];
    off_t recv_offset = 0;
    int times = 10;

    // 循环接收文件内容
    while (1)
    {
        recv(sockfd, &recv_tlv, TLV_HEAD_SIZE, MSG_WAITALL);
        if (recv_tlv.type == TYPE_ABORT)
        {
            break;
        }
        recv(sockfd, &data, recv_tlv.length, MSG_WAITALL);

        write(fd, data, recv_tlv.length); // 将接收到的数据写入fd文件描述符指向的文件

        // 更新接收数据量
        recv_offset += recv_tlv.length;
        --times;
        if (times == 0 || recv_offset >= CHUNK_UPDATE)
        {
            updateFileInfo(mysql, recv_offset, file_check->sha256, FILE_SEND);
            times = 0;
            recv_offset = 0;
        }
    }

    // 最后一次收到，校验hash
    lseek(fd, 0, SEEK_SET);
    calculateSHA256(fd, sha256);
    int cmp = strncmp(sha256, file_check->sha256, SHA256_LENGTH);
    if (cmp == 0)
    {
        // 更新file_size、completed_file
        updateFileInfo(mysql, file_check->file_size, file_check->sha256, FILE_LAST_SEND);
        printf("传输成功\n");
        free(data);
        return 0;
    }
    else
    {
        printf("传输有误，删除文件\n");
        deleteFile(mysql, user_id, file_check->file_name, file_path);
        free(data);
        return -1;
    }
}